/*-------------------------------------------------------------------------
 *
 * pg_cast.c
 *	  支持pg_cast关系操作的常规例程
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/catalog/pg_cast.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h"
#include "utils/rel.h"
#include "utils/syscache.h"

 /*
 * ----------------------------------------------------------------
 *		CastCreate
 *
 * 为新创建的转换形成并插入目录元组。
 * 调用方必须已经检查了权限，并对给定的数据类型和转换函数
 * （如适用）进行了一致性检查。
 *
 * 'behavior' 表示新转换在其输入和输出类型及转换函数上
 * 的依赖类型。
 * ----------------------------------------------------------------
 */
ObjectAddress CastCreate(Oid fc_sourcetypeid, Oid fc_targettypeid, Oid fc_funcid, char fc_castcontext,
		   char fc_castmethod, DependencyType fc_behavior)
{
	Relation	fc_relation;
	HeapTuple	fc_tuple;
	Oid			fc_castid;
	Datum		fc_values[Natts_pg_cast];
	bool		fc_nulls[Natts_pg_cast];
	ObjectAddress fc_myself,
				fc_referenced;
	ObjectAddresses *fc_addrs;

	fc_relation = table_open(CastRelationId, RowExclusiveLock);

	 /*
	 * 检查重复项。这只是为了提供一个友好的错误消息，
	 * 唯一索引无论如何都会捕获它（所以不用担心竞争
	 * 条件）。
	 */
	fc_tuple = SearchSysCache2(CASTSOURCETARGET,
							ObjectIdGetDatum(fc_sourcetypeid),
							ObjectIdGetDatum(fc_targettypeid));
	if (HeapTupleIsValid(fc_tuple))
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_OBJECT),
				 errmsg("cast from type %s to type %s already exists",
						format_type_be(fc_sourcetypeid),
						format_type_be(fc_targettypeid))));

	 /* 准备就绪 */
	fc_castid = GetNewOidWithIndex(fc_relation, CastOidIndexId, Anum_pg_cast_oid);
	fc_values[Anum_pg_cast_oid - 1] = ObjectIdGetDatum(fc_castid);
	fc_values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(fc_sourcetypeid);
	fc_values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(fc_targettypeid);
	fc_values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(fc_funcid);
	fc_values[Anum_pg_cast_castcontext - 1] = CharGetDatum(fc_castcontext);
	fc_values[Anum_pg_cast_castmethod - 1] = CharGetDatum(fc_castmethod);

	MemSet(fc_nulls, false, sizeof(fc_nulls));

	fc_tuple = heap_form_tuple(RelationGetDescr(fc_relation), fc_values, fc_nulls);

	CatalogTupleInsert(fc_relation, fc_tuple);

	fc_addrs = new_object_addresses();

	/* 创建依赖项条目 */  
	ObjectAddressSet(fc_myself, CastRelationId, fc_castid);

	 /* 对源类型的依赖 */
	ObjectAddressSet(fc_referenced, TypeRelationId, fc_sourcetypeid);
	add_exact_object_address(&fc_referenced, fc_addrs);

	 /* 对目标类型的依赖 */
	ObjectAddressSet(fc_referenced, TypeRelationId, fc_targettypeid);
	add_exact_object_address(&fc_referenced, fc_addrs);

	 /* 对函数的依赖 */
	if (OidIsValid(fc_funcid))
	{
		ObjectAddressSet(fc_referenced, ProcedureRelationId, fc_funcid);
		add_exact_object_address(&fc_referenced, fc_addrs);
	}

	record_object_address_dependencies(&fc_myself, fc_addrs, fc_behavior);
	free_object_addresses(fc_addrs);

	/* 对扩展的依赖 */
	recordDependencyOnCurrentExtension(&fc_myself, false);

	 /* 新转换的后创建钩子 */
	InvokeObjectPostCreateHook(CastRelationId, fc_castid, 0);

	heap_freetuple(fc_tuple);

	table_close(fc_relation, RowExclusiveLock);

	return fc_myself;
}
